﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using ProtoBuf;
using tutorial;
using LitJson;
namespace Text1
{
    public class SockedClient
    {
        const int BufferSize = 8192; //定义buffer缓冲区长度 
        NetworkStream stream;
        byte[] buffer = new byte[BufferSize];
        TcpClient client;
        MemoryStream mem;//缓存流
        BinaryReader reader;//缓存流读取器
        public SockedClient(TcpClient _client)
        {
            client = _client;
            Console.WriteLine("客户端连接成功" + client.Client.RemoteEndPoint);
            stream = client.GetStream();//获取网络流
            mem = new MemoryStream();
            reader = new BinaryReader(mem);
            //开启异步读取数据
            stream.BeginRead(buffer, 0, BufferSize, Read, null);
        }

        //子线程读取消息
        private void Read(IAsyncResult ar)
        {
            try
            {
                int readCount = stream.EndRead(ar);
                if (readCount == 0) throw new Exception("读取异常");
                //接受一次把消息给逻辑层
                OnReceive(buffer, readCount);
                lock (client)
                {
                    Array.Clear(buffer, 0, BufferSize);
                    stream.BeginRead(buffer, 0, BufferSize, Read, null);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                OnDisconnect();
            }
        }
        //逻辑层 解包 处理[长度+消息] 
        void OnReceive(byte[] bytes, int count)
        {
            mem.Seek(0, SeekOrigin.End);//指针指到最后
            mem.Write(bytes, 0, count);//消息往后追加
            mem.Seek(0, SeekOrigin.Begin);//指针指到开头
            while (RemaindLength() > 4)//判断剩余长度是否够一个int32的长度
            {
                //获取消息长度 指针后移4位
                int length = reader.ReadInt32();
                if (RemaindLength() >= length)//剩余字节数是否大于消息长度
                {
                    byte[] content = reader.ReadBytes(length);
                    OnMessage(content);
                }
                else
                {
                    mem.Seek(-4, SeekOrigin.Current);//把指针前移四位 保证消息的完整性
                    break;
                }
                byte[] remain = reader.ReadBytes(RemaindLength());//把剩余的半包读取出来
                mem.SetLength(0);//清除缓存流
                mem.Write(remain, 0, remain.Length);//写入剩余的半包
            }
        }
        //接到一条消息
        void OnMessage(byte[] content)
        {
            //转发
            GameSever.OnEvent(this, new ByteBuffer(content));
            //打印
            string msg = Encoding.UTF8.GetString(content);
        }

        //解析二进制格式序列化
        object ReadBinaryFormat(byte[] bytes)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                ms.Write(bytes, 0, bytes.Length);
                ms.Flush();
                ms.Position = 0;

                var format = new BinaryFormatter();
                var obj = format.Deserialize(ms);
                return obj;
            }
        }
        //获取剩余字节长度
        int RemaindLength()
        {
            return (int)(mem.Length - mem.Position);
        }
        //客户端断开连接
        void OnDisconnect()
        {
            GameSever.Instance.DisConnect(this);
            stream.Close();//关流
            client.Close();//关客户端
        }
        void Write(byte[] content)
        {
            ByteBuffer buf = new ByteBuffer();
            buf.WriteInt(content.Length);
            buf.WriteBytes(content);        
            byte[] bytes = buf.ToBytes();
            stream.Write(bytes, 0, bytes.Length);
        }
        public void Send(Protocal type, string msg)
        {
            ByteBuffer buf = new ByteBuffer();
            buf.WriteByte((byte)type);
            buf.WriteString(msg);

            Write(buf.ToBytes());
        }
        public void Send(Protocal type, byte[] content)
        {
            ByteBuffer buf = new ByteBuffer();
            buf.WriteByte((byte)type);
            buf.WriteBytes(content);

            Write(buf.ToBytes());
        }
    }
}
